/**
 * Created by AMD on 06.11.14.
 */
package controller {
import flash.geom.Point;
import flash.geom.Point;
import flash.geom.Point;
import flash.geom.Point;
import flash.utils.Timer;

import messages.DebugMessage;

import model.Constants;
import model.PrototypeProxy;

import model.RuntimeProxy;
import model.objects.CellData;
import model.objects.ProductData;
import model.objects.ProductWarehouseData;
import model.objects.ShelfData;
import model.objects.ShopObjectData;
import model.objects.ShopObjectData;
import model.prototypes.ShelfProto;

import mvcexpress.mvc.PooledCommand;

import starling.events.Touch;
import starling.events.TouchPhase;

public class GameLayerTouchCommand extends PooledCommand{
    [Inject]
    public var runtimeProxy:RuntimeProxy;

    [Inject]
    public var prototypeProxy:PrototypeProxy;

    private var _dragTimer:Timer = new Timer(50);
    private var _bufPoint:Point = new Point();
    private var _bufNumber:Number = 0;
    private var _bufTouch:Touch;
    private var _bufAngle:int = 0;
    public function execute(params:Object):void {
        trace("GameLayerTouchCommand.execute(" + params.touch.target + ")");

        this._bufTouch = params.touch as Touch;
        switch (runtimeProxy.mode){
            case Constants.MODE_SIMULATION:
                this._processDrag(this._bufTouch);
                this._processHighlight(this._bufTouch, params.quad, params.quad_old, 1);
                if(this._isClick(this._bufTouch)){
                    _testDeleteProduct(params.quad);
                }
                    //TODO: make move detecting function
                break;
            case Constants.MODE_INTERIOR:
                this._processDrag(this._bufTouch);

                //this._processHighlight(this._bufTouch, params.quad, params.quad_old, 2);
                if(this._isClick(this._bufTouch)){
                    //this._processMoveShopObject(this._bufTouch, params.quad);
                } //else {
                    this._processShopObjectContextMenu(this._bufTouch, params.quad, params.quad_old);
                    this._processWallObjectContextMenu(this._bufTouch, params.quad, params.quad_old);
                //}
                break;
            case Constants.MODE_SIMULATION_PLACE_PRODUCT:
                this._processDrag(this._bufTouch);
                if(this._isClick(this._bufTouch)){
                    this._addProduct(params.quad);
                }
                break;
            case Constants.MODE_INTERIOR_PLACE_FLOOR:
                this._processDrag(this._bufTouch);
                if(this._isClick(this._bufTouch)){
                    this._placeFloor(params.quad);
                }
                break;
            case Constants.MODE_INTERIOR_PLACE_WALL:
                this._processDrag(this._bufTouch);
                if(this._isClick(this._bufTouch)){
                    this._placeWall(params.quad,runtimeProxy.modeParams.full_sprite_name);
                }
                break;
            case Constants.MODE_INTERIOR_MOVE_WALL_COVER:
            case Constants.MODE_INTERIOR_PLACE_WALL_COVER:
                this._processDrag(this._bufTouch);
                if(this._isClick(this._bufTouch)){
                    this._bufPoint = params.quad;
                    if(runtimeProxy.canPlaceWallObject(this._bufPoint)){
                        if(runtimeProxy.mode.indexOf("WALL_COVER") >= 0){
                             if(runtimeProxy.shopDesign.setWallCoverAtQuad(this._bufPoint,runtimeProxy.modeParams.object.full_sprite_name)){
                                 if(runtimeProxy.mode == Constants.MODE_INTERIOR_MOVE_WALL_COVER){
                                     runtimeProxy.setMode(Constants.MODE_INTERIOR, {});
                                 }
                                    //TODO: count money and cashing

                             }
                        }
                    }
                }
                break;
            case Constants.MODE_INTERIOR_PLACE_DOOR:
            case Constants.MODE_INTERIOR_MOVE_DOOR:
                this._processDrag(this._bufTouch);
                    if(this._isClick(this._bufTouch)){
                        //TODO: place door
                        this._bufPoint = params.quad;
                        if(runtimeProxy.canPlaceWallObject(this._bufPoint)){
                            if(this._bufPoint.x != 0 && this._bufPoint.y != 0){
                                var _point:Point = this._bufPoint.clone();
                                if(_point.x == -1) _point.x = 0;
                                if(_point.y == -1) _point.y = 0;
                                var _bufCellData:CellData = runtimeProxy.getCellData(_point);
                                if(_bufCellData.occ_var <= 0){
                                    if(runtimeProxy.shopDesign.setDoorAtQuad(this._bufPoint,runtimeProxy.modeParams.object.full_sprite_name)){
                                        if(runtimeProxy.mode == Constants.MODE_INTERIOR_MOVE_DOOR){
                                            runtimeProxy.setMode(Constants.MODE_INTERIOR, {});
                                        }
                                    }
                                }
                            }
                        }
                    }
                break;
            case Constants.MODE_INTERIOR_MOVE_SHELF:
            case Constants.MODE_INTERIOR_PLACE_SHELF:
                this._processDrag(this._bufTouch);
                //this._bufAngle = runtimeProxy.modeParams.angle;
                if(this._isClick(this._bufTouch)){
                    var _bufShopObject:ShopObjectData = runtimeProxy.modeParams.object;
                    if(runtimeProxy.canBePlaced(_bufShopObject.proto, params.quad, _bufShopObject.angle)){
                        _bufShopObject.position = Point(params.quad);
                        runtimeProxy.placeShopObject(_bufShopObject);
                        if(runtimeProxy.mode == Constants.MODE_INTERIOR_MOVE_SHELF){
                            runtimeProxy.setMode(Constants.MODE_INTERIOR, {});
                            runtimeProxy.removeAllHighlights();
                        } else {
                            //TODO: check enough money and cashing
                        }
                    }
                } else if(this._bufTouch.phase == TouchPhase.HOVER){
                    runtimeProxy.highlightOccMatrix((runtimeProxy.modeParams.object as ShopObjectData).rotatedOCCMatrix, params.quad);
                }
                break;
        }
    }

    private var _bufFloorStr:String;
    private function _placeFloor(quad:Point):void {
        this._bufFloorStr = runtimeProxy.shopDesign.getFloorAt(quad)
        if(this._bufFloorStr != null && runtimeProxy.modeParams.full_sprite_name != this._bufFloorStr){
            runtimeProxy.shopDesign.setFloorAt(quad, runtimeProxy.modeParams.full_sprite_name);
        }
    }
    private var _bufWallStr:String;
    private function _placeWall(quad:Point, wallSpriteFullName:String):void {
        if(quad.x == -1){
            this._bufWallStr = runtimeProxy.shopDesign.getWallAtY(quad.y)
        }else if (quad.y == -1){
            this._bufWallStr = runtimeProxy.shopDesign.getWallAtX(quad.x)
        } else {
            return;
        }
        if(this._bufWallStr != null && wallSpriteFullName != this._bufWallStr){
            if(quad.y == -1){
                runtimeProxy.shopDesign.setWallAtX(quad.x, wallSpriteFullName);
            }else if (quad.x == -1){
                runtimeProxy.shopDesign.setWallAtY(quad.y, wallSpriteFullName);
            }
        }
    }

    private var _productWarehouseData:ProductWarehouseData;
    private var _productDataBuf:ProductData;
    private var _needAmount:int;
    private var _bufSlotNum:int;
    private var _shelfDataBuf:ShelfData;
    private function _addProduct(quad:Point):void {
        this._productWarehouseData = runtimeProxy.modeParams.product as ProductWarehouseData;

        this._bufShopObject = runtimeProxy.getCellData(quad).getPlacedObject();
        if(this._bufShopObject != null){
            if(this._bufShopObject.proto.type == Constants.TYPE_SHELF){// объект в квадрате является полкой
                this._shelfDataBuf = (this._bufShopObject as ShelfData);
                this._bufSlotNum = this._shelfDataBuf.getUncompletedSlotNum(this._productWarehouseData.proto.productId);//проверяем, есть ли неполные слоты с таким же продуктом
                this._productDataBuf = null;
                if(this._bufSlotNum >= 0){//неполный слоты с таким же продуктом найден, запоминаем
                    this._productDataBuf = this._shelfDataBuf.products[this._bufSlotNum];
                }
                if(this._productDataBuf == null){
                    this._bufSlotNum = this._shelfDataBuf.getFreeSlotNum();//ищем свободный слот, если не нашли нужный
                }

                if(this._bufSlotNum >= 0){//если нашли подходящий слот (свободный или не до конца заполненный данным продуктом)
                    if(this._productDataBuf == null){//проверка на свободный слот
                        this._productDataBuf = new ProductData(this._productWarehouseData.proto);
                        this._productDataBuf.count = 0;
                    }
                    //определяем количество товара для полного заполнения слота
                    this._needAmount = int((this._bufShopObject.proto as ShelfProto).partVolume/this._productWarehouseData.proto.volume) - this._productDataBuf.count;
                    if(_productWarehouseData.count < _needAmount){
                        this._needAmount = _productWarehouseData.count;
                    }
                    //заполняем слот
                    this._productDataBuf.count += _needAmount;
                    (this._bufShopObject as ShelfData).setProductOn(this._bufSlotNum,this._productDataBuf);

                    //убираем нужное количество товара со склада
                    this._productWarehouseData.count -= this._needAmount;

                    if(this._productWarehouseData.count == 0){
                        runtimeProxy.warehouseData.updateCellData(runtimeProxy.modeParams.cell_num,null);
                        runtimeProxy.setMode(Constants.MODE_SIMULATION, null);
                    } else {
                        runtimeProxy.warehouseData.updateCellData(runtimeProxy.modeParams.cell_num,this._productWarehouseData)
                    }
                }
            }
        }
    }

    private function _testDeleteProduct(quad:Point):void {
        this._bufShopObject = runtimeProxy.getCellData(quad).getPlacedObject();
        if(this._bufShopObject != null){
            if(this._bufShopObject.proto.type == Constants.TYPE_SHELF){
                (this._bufShopObject as ShelfData).deleteProductOn(1);
            }
        }
    }

    private function _isClick(touch:Touch):Boolean {
        if(touch.phase == TouchPhase.ENDED){
            if(Point.distance(new Point(touch.globalX,touch.globalY), runtimeProxy.dragSnapPoint) < 5){
                //click
               return true;
            }
        }
        return false;
    }

    private function _processDrag(touch:Touch):void {
        if(touch.phase == TouchPhase.BEGAN){
            _dragTimer.reset();
            _dragTimer.start();
            runtimeProxy.dragSnapPoint = new Point(touch.globalX,touch.globalY);
            runtimeProxy.dragGameLayer = true;
        } else if(touch.phase == TouchPhase.ENDED){
            _dragTimer.stop();
            this._bufPoint.setTo(touch.globalX,touch.globalY);
            //trace("dragDistance = "+Point.distance(this._bufPoint,runtimeProxy.dragSnapPoint))
            this._bufPoint = this._bufPoint.subtract(runtimeProxy.dragSnapPoint);
            _bufNumber = _dragTimer.currentCount;
            if(_bufNumber > 5) _bufNumber = 0;
            if(_bufNumber !=0 ){
                _bufNumber = 1/_bufNumber;
                _bufPoint.x *= _bufNumber;
                _bufPoint.y *= _bufNumber;
            }else {
                _bufPoint.x = _bufPoint.y = 0;
            }
            runtimeProxy.dragInertion = _bufPoint.clone();
            runtimeProxy.dragGameLayer = false;
        }
    }


    private var _bufShopObject:ShopObjectData;
    private function _processHighlight(touch:Touch, quad:Point, quad_old:Point, highlightMode:int):void {
        if(touch.phase == TouchPhase.HOVER){
            this._bufShopObject = runtimeProxy.getCellData(quad_old).getPlacedObject();
            if(this._bufShopObject != null){
                if(this._bufShopObject.proto.type == Constants.TYPE_SHELF){
                    this._bufShopObject.highlightMode = 0;
                }
            }

            this._bufShopObject = runtimeProxy.getCellData(quad).getPlacedObject();
            if(this._bufShopObject != null){
                if(this._bufShopObject.proto.type == Constants.TYPE_SHELF){
                    this._bufShopObject.highlightMode = highlightMode;
                }
            }
        }
    }
    private var _lastQuadWithObject:Point = new Point();
    private function _processShopObjectContextMenu(touch:Touch, quad:Point, quad_old:Point):void {
        if(touch.phase == TouchPhase.HOVER || touch.phase == TouchPhase.ENDED){
            this._bufShopObject = runtimeProxy.getCellData(quad).getPlacedObject();
            if(this._bufShopObject != null){
                this._lastQuadWithObject.copyFrom(quad);
                if(runtimeProxy.contextMenuTarget != null && runtimeProxy.contextMenuTarget == this._bufShopObject){
                    return;
                }
                if(this._bufShopObject.proto.type == Constants.TYPE_SHELF){
                    this._contextMenuClearTarget();
                    runtimeProxy.contextMenuTarget = this._bufShopObject;
                    runtimeProxy.contextMenuTarget.highlightMode = 2;
                }
            } else if(quad_old == null || Point.distance(this._lastQuadWithObject,quad) > 1.6){
                this._contextMenuClearTarget();
            }
        }else if(touch.phase == TouchPhase.BEGAN){
            this._contextMenuClearTarget();
        }
    }
    private function _processWallObjectContextMenu(touch:Touch, quad:Point, quad_old:Point):void {
        if(touch.phase == TouchPhase.HOVER || touch.phase == TouchPhase.ENDED){
            this._bufWallStr = null;

            if(runtimeProxy.shopDesign.quadIsInside(quad.x,quad.y) == false){
                this._contextMenuClearTarget();
                this._bufWallStr = runtimeProxy.shopDesign.getWallCoverAtQuad(quad);
                if(this._bufWallStr != null){
                    runtimeProxy.wallObjectContextMenuTarget = {full_sprite_name:this._bufWallStr, is_door:false, quad:quad.clone()};
                } else {
                    this._bufWallStr = runtimeProxy.shopDesign.getDoorAtQuad(quad);
                    if(this._bufWallStr != null){
                        runtimeProxy.wallObjectContextMenuTarget = {full_sprite_name:this._bufWallStr, is_door:true, quad:quad.clone()};
                    }
                }
            }

            if(this._bufWallStr == null){
                if(quad_old == null || (runtimeProxy.wallObjectContextMenuTarget != null && Point.distance(runtimeProxy.wallObjectContextMenuTarget.quad,quad) > 1.6)){
                    runtimeProxy.wallObjectContextMenuTarget = null;
                }
            }
        } else if(touch.phase == TouchPhase.BEGAN){
            runtimeProxy.wallObjectContextMenuTarget = null;
        }
        //TODO: work on it (+make wall covers highlighting)
    }

    private function _contextMenuClearTarget():void {
        if(runtimeProxy.contextMenuTarget){//disable highlighting on old contextMenuTarget
            runtimeProxy.contextMenuTarget.highlightMode = 0;
        }
        runtimeProxy.contextMenuTarget = null;
    }


}
}
